﻿using System;
using System.IO;
using System.Numerics;
using System.Windows;
using System.Windows.Controls;
using Core;
using Microsoft.Win32;

namespace KeyGenerator
{
    /// <summary>
    /// Interaction logic for GenerateKeys.xaml
    /// </summary>
    public partial class GenerateKeys : UserControl
    {
        public GenerateKeys()
        {
            InitializeComponent();
        }

        private void buttonGenerateKey_Click(object sender, RoutedEventArgs e)
        {
            if (ValidateForm())
            {
                BigInteger m = RSA.GenerateM(BigInteger.Parse(textBoxP.Text), BigInteger.Parse(textBoxQ.Text));

                if (ValidateE(m))
                {
                    DateTime timeStart = DateTime.Now;

                    BigInteger n = RSA.GenerateN(BigInteger.Parse(textBoxP.Text), BigInteger.Parse(textBoxQ.Text));
                    BigInteger d = RSA.GenerateDecryptKey(BigInteger.Parse(textBoxE.Text), m);

                    // Update Output Form
                    textBoxPublicKey.Text = textBoxE.Text;
                    textBoxPrivateKey.Text = d.ToString();
                    textBoxN.Text = n.ToString();

                    // Show calculation time
                    ShowCalculationTime(timeStart, DateTime.Now, "Generate key finished.");
                }
            }
        }

        private bool ValidateForm()
        {
            return ValidateNumber("P", textBoxP.Text) && ValidateNumber("Q", textBoxQ.Text) && NotSamePQ();
        }

        private bool NotSamePQ()
        {
            if (textBoxP.Text == textBoxQ.Text)
            {
                ShowError("P and Q is same.");
                return false;
            }

            return true;
        }

        private bool ValidateE(BigInteger M)
        {
            string s = textBoxE.Text;
            string box = "E";

            BigInteger bi;
            if (s.Length < 1)
            {
                ShowError(box + " is empty.");
                return false;
            }

            if (!BigInteger.TryParse(s, out bi))
            {
                ShowError(box + " is not a number.");
                return false;
            }

            if (!RSA.isRelativePrime(BigInteger.Parse(s), M))
            {
                ShowError(box + " is not relavite a prime with M (P - 1 * Q - 1).");
                return false;
            }

            return true;
        }

        private bool ValidateNumber(string box, string s)
        {
            BigInteger bi;
            if (s.Length < 1)
            {
                ShowError(box + " is empty.");
                return false;
            }

            if (!BigInteger.TryParse(s, out bi))
            {
                ShowError(box + " is not a number.");
                return false;
            }

            if (!RSA.isPrime(BigInteger.Parse(s)))
            {
                ShowError(box + " is not a prime.");
                return false;
            }

            return true;
        }

        private void ShowError(string msg)
        {
            MessageBox.Show(msg, "Error");
        }

        private void buttonSaveEncKey_Click(object sender, RoutedEventArgs e)
        {
            saveFile(textBoxPublicKey.Text, "pub files|*.pub");
        }

        private void buttonSaveDecKey_Click(object sender, RoutedEventArgs e)
        {
            saveFile(textBoxPrivateKey.Text, "pri files|*.pri");
        }

        private void buttonSaveNValue_Click(object sender, RoutedEventArgs e)
        {
            saveFile(textBoxN.Text, "n files|*.n");
        }

        private void saveFile(String text, string filter)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = filter;
            sfd.AddExtension = true;
            sfd.RestoreDirectory = true;
            String fileName = null;

            // Show save file dialog
            if (sfd.ShowDialog() == true)
            {
                fileName = sfd.FileName;

                if (fileName != null)
                {
                    // Save file
                    MemoryStream stream = new MemoryStream(Converter.ToBytes(text));
                    SaveMemoryStream(stream, fileName);
                }
            }
        }

        protected void SaveMemoryStream(MemoryStream ms, String fileName)
        {
            FileStream outStream = File.OpenWrite(fileName);
            ms.WriteTo(outStream);
            outStream.Flush();
            outStream.Close();
        }

        protected void ShowCalculationTime(DateTime timeStart, DateTime timeEnd, string msg)
        {
            TimeSpan t = timeEnd - timeStart;
            MessageBox.Show(msg + " Calculation time " + t.Milliseconds + " miliseconds.", "Result");
        }
    }
}
